#include <algorithm>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <string>
#include <vector>
#include <cstring>
#include <ctime>
#include <openssl/md5.h>
#include <sys/ioctl.h>
#include <cpuid.h>
#include <net/if.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

class HardwareIDGenerator {
private:
    // 自定义Base32字符集 (0-9, A-X 去除 O,I)
    const std::string BASE32_CHARS = "0123456789ABCDEFGHJKLMNPQRSTUVWX";
    
public:
    // 获取CPU信息
    std::string getCPUInfo() {
        uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
        // 使用CPUID指令获取处理器信息
        if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
            uint64_t cpuId = (static_cast<uint64_t>(edx) << 32) | eax;
            cpuId ^= (static_cast<uint64_t>(ecx) << 32) | (ebx&0x00FFFFFF);
            return std::to_string(cpuId);
        }
       
        return "00000";
    }
    
    // 获取MAC地址
    std::string getMACAddress() {
        std::string macAddress = "00:00:00:00:00:00";
        int fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (fd >= 0) {
            struct ifreq ifr;
            struct ifconf ifc;
            char buf[1024];
            
            ifc.ifc_len = sizeof(buf);
            ifc.ifc_buf = buf;
            
            if (ioctl(fd, SIOCGIFCONF, &ifc) == 0) {
                struct ifreq* it = ifc.ifc_req;
                const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
                
                for (; it != end; ++it) {
                    strcpy(ifr.ifr_name, it->ifr_name);  
                    if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
                        unsigned char* mac = (unsigned char*)ifr.ifr_hwaddr.sa_data;                    
                        // 跳过回环接口和全零MAC
                        if (strcmp(ifr.ifr_name, "lo") != 0 && 
                            !(mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && 
                              mac[3] == 0 && mac[4] == 0 && mac[5] == 0)) {
                                std::stringstream ss;
                                ss << std::hex << std::setfill('0');
                                for (int i = 0; i < 6; i++) {
                                    ss << std::setw(2) << static_cast<unsigned int>(mac[i]);
                                    if (i < 5) ss << ":";
                                    }
                                macAddress = ss.str();                                       
                                break;
                        }
                    }
                }
            }
            close(fd);
        }
        return macAddress;
    }
    
    // 获取硬盘序列号
    std::string getDiskSerial() {
        std::string serial = "UnknownDisk";
        std::vector<std::string> disks = {"sda", "vda", "xvda", "nvme0n1", "hda"};
    
        for (const auto& disk : disks) {
            std::string diskPath = "/dev/" + disk;
            if (access(diskPath.c_str(), F_OK) != 0) {
                continue;
            }
            
            // 读取sysfs中的序列号
            std::string serialPath = "/sys/block/" + disk + "/device/serial";
            std::ifstream serialFile(serialPath);
            if (serialFile.is_open()) {
                std::string serial;
                std::getline(serialFile, serial);
                serialFile.close();
                
                if (!serial.empty()) {
                    // 移除空格和换行符
                    serial.erase(std::remove(serial.begin(), serial.end(), ' '), serial.end());
                    serial.erase(std::remove(serial.begin(), serial.end(), '\n'), serial.end());
                    if (!serial.empty()) {
                        std::cout << "通过sysfs找到磁盘序列号: " << serial << " (设备: " << disk << ")" << std::endl;
                        return serial;
                    }
                }
            }
        }
        // 备用方案：使用stat获取文件系统信息
        struct stat statBuf;
        if (stat("/", &statBuf) == 0) {
            std::stringstream ss;
            ss << statBuf.st_dev;
            serial = ss.str();
        }
        return serial;
    }
    
    // 计算MD5哈希
    std::string calculateMD5(const std::string& input) {
        unsigned char digest[MD5_DIGEST_LENGTH];
        MD5((unsigned char*)input.c_str(), input.length(), digest);
        
        std::stringstream ss;
        ss << std::hex << std::setfill('0');
        for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
            ss << std::setw(2) << static_cast<unsigned int>(digest[i]);
        }
        
        return ss.str();
    }
    
    // 自定义Base32编码
    std::string customBase32Encode(const std::string& input) {
        std::string output;
        std::vector<unsigned char> bytes;
        
        // 将十六进制字符串转换为字节
        for (size_t i = 0; i < input.length(); i += 2) {
            unsigned char byte = std::stoul(input.substr(i, 2), nullptr, 16);
            bytes.push_back(byte);
        }
        
        // Base32编码
        int buffer = 0;
        int bitsLeft = 0;
        
        for (unsigned char byte : bytes) {
            buffer = (buffer << 8) | byte;
            bitsLeft += 8;
            
            while (bitsLeft >= 5) {
                bitsLeft -= 5;
                int index = (buffer >> bitsLeft) & 0x1F;
                output += BASE32_CHARS[index];
            }
        }
        
        if (bitsLeft > 0) {
            int index = (buffer << (5 - bitsLeft)) & 0x1F;
            output += BASE32_CHARS[index];
        }
        
        return output;
    }
    
    // 格式化ID为xxxxx-xxxxx-xxxxx-xxxxx-xxxxx格式
    std::string formatID(const std::string& id) {
        std::string formatted;
        for (size_t i = 0; i < id.length(); i++) {
            if (i > 0 && i % 5 == 0) {
                formatted += "-";
            }
            formatted += id[i];
        }
        return formatted;
    }
    
    // 生成硬件ID
    std::string generateHardwareID() {
        std::string hardwareInfo = getCPUInfo() + getMACAddress() + getDiskSerial();
        std::string md5Hash = calculateMD5(hardwareInfo);
        std::string base32Encoded = customBase32Encode(md5Hash);
        
        // 确保长度足够
        if (base32Encoded.length() < 25) {
            base32Encoded += std::string(25 - base32Encoded.length(), '0');
        }
        
        return formatID(base32Encoded.substr(0, 25));
    }
    
    // 生成注册码
    std::string generateRegistrationCode(const std::string& hardwareID, int validDays) {
        // 获取到期时间戳（精确到天）
        std::time_t now = std::time(nullptr);
        std::time_t expiry = now + (validDays * 24 * 60 * 60);
        std::tm* tm_expiry = std::gmtime(&expiry);
        
        std::stringstream dateSS;
        dateSS << std::setfill('0') << std::setw(4) << (tm_expiry->tm_year + 1900)
               << std::setw(2) << (tm_expiry->tm_mon + 1)
               << std::setw(2) << tm_expiry->tm_mday;
        
        std::string combined = hardwareID + "|" + dateSS.str();
        std::string md5Hash = calculateMD5(combined);
        std::string base32Encoded = customBase32Encode(md5Hash);
        
        // 确保长度足够
        if (base32Encoded.length() < 25) {
            base32Encoded += std::string(25 - base32Encoded.length(), '0');
        }
        
        return formatID(base32Encoded.substr(0, 25));
    }
    
    // 验证注册码
    bool verifyRegistrationCode(const std::string& hardwareID, const std::string& registrationCode) {
        // 从注册码反推有效期
        std::string cleanRegCode = registrationCode;
        cleanRegCode.erase(std::remove(cleanRegCode.begin(), cleanRegCode.end(), '-'), cleanRegCode.end());
        
        if (cleanRegCode.length() != 25) {
            return false;
        }
        
        // 尝试不同的天数来验证
        for (int days = 1; days <= 3650; days++) { // 最多验证10年
            std::string testCode = generateRegistrationCode(hardwareID, days);
            if (testCode == registrationCode) {
                // 检查是否过期
                std::time_t now = std::time(nullptr);
                std::time_t expiry = now + (days * 24 * 60 * 60);
                return expiry > now;
            }
        }
        
        return false;
    }
};

bool IsPassOk(const char *lpszPassFile)
{
    char sT[32];
    HardwareIDGenerator generator;
    FILE *fp = fopen(lpszPassFile, "a+t");
    if (fp != NULL)
    {
        fread(sT, 29, 1, fp);
    }
    sT[29] = 0;
    std::string regCode = sT;
    std::string hardwareId = generator.generateHardwareID();
    bool isValid = generator.verifyRegistrationCode(hardwareId, regCode);
    if (isValid)
    {
        fclose(fp);
        return true;
    }
    else
    {
        ftruncate(fileno(fp), 0);
        fwrite(hardwareId.data(), 29, 1, fp);
        fclose(fp);
        return false;
    }
}

int main(int argc, char **argv)
{
    std::string id;
    int day = 30;
    if(argc > 2)
    {
        day = atoi(argv[2]);
    }
    if(argc > 1)
    {
        id = argv[1];
    }
    std::cout << "用法：" << argv[0] << " xxxxx-xxxxx-xxxxx-xxxxx-xxxxx [30]" << std::endl;
    HardwareIDGenerator generator;
    if (id.length() == 29)
    {
        std::cout << id << "\t" << day << " 天有效期的注册码为：" << std::endl;
        std::cout << generator.generateRegistrationCode(id, day) << std::endl << std::endl;      
    }

    // 生成硬件ID
    std::string hardwareID = generator.generateHardwareID();
    std::cout << "硬件ID: " << hardwareID << std::endl;
    
    // 生成30天有效的注册码
    std::string regCode = generator.generateRegistrationCode(hardwareID, 30);
    std::cout << "注册码: " << regCode << std::endl;
    
    // 验证注册码
    bool isValid = generator.verifyRegistrationCode(hardwareID, regCode);
    std::cout << "注册码验证: " << (isValid ? "有效" : "无效") << std::endl;
    
    // 测试修改注册码的情况
    std::string modifiedRegCode = regCode;
    if (!modifiedRegCode.empty()) {
        modifiedRegCode[0] = (modifiedRegCode[0] == 'A') ? 'B' : 'A';
    }
    bool isModifiedValid = generator.verifyRegistrationCode(hardwareID, modifiedRegCode);
    std::cout << "修改后注册码验证: " << (isModifiedValid ? "有效" : "无效") << std::endl;
    
    isModifiedValid = IsPassOk("pass.txt");
    std::cout << "注册码验证: " << (isModifiedValid ? "成功" : "失败") << std::endl;

    return 0;
}